﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JeuDeDames;

namespace JeuDeDames
{
    public abstract class Joueur
    {
        public const int BLANC = -1;
        public const int NOIR = 1;

        public string nom;
        public int couleur; /*-1 Blancs; 1 Noirs*/
        public List<Piece> lesPieces;
        public List<Coup> coupsPossibles;
        public int[] indicePromote;
        public bool monTour;    /*true si c'est à ce joueur de jouer, false sinon*/

        public abstract void jouer(Coup coup, Damier damier);

        //TODO gerer Dames
        //calcul la liste des coups possibles pour le joueur
        public void calculCoupsPossibles(Damier damier)
        {
            List<Coup> coupsPossiblesSansPrise = new List<Coup>();
            List<Coup> coupsPossiblesAvecPrise = new List<Coup>();

            // set les deux directions possibles suivant la couleur du joueur
            int directionUn = 11 * this.couleur;
            int directionDeux = 13 * this.couleur;

            foreach (Piece piece in lesPieces)
            {
                /*Essais de voir si la possition de la pièce + la directionUn est un coup valide*/
                try
                {
                    /*Si le coup dois manger*/
                    if ((Damier.damier[piece.position + (directionUn * 2)] as CaseNoire).estVide() && !this.lesPieces.Contains((Damier.damier[piece.position + (directionUn)] as CaseNoire).piece) && !(Damier.damier[piece.position + directionUn] as CaseNoire).estVide()) //test manger 1er cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position + (directionUn * 2)] as CaseNoire, (Damier.damier[piece.position + directionUn] as CaseNoire).piece);
                        coupsPossiblesAvecPrise.Add(unCoup);
                    }
                    /*Si le coup est un déplacement*/
                    else if (coupsPossiblesAvecPrise.Count() == 0 && (Damier.damier[piece.position + directionUn] is CaseNoire) && (Damier.damier[piece.position + directionUn] as CaseNoire).estVide()) //test deplacement 1er cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position + directionUn] as CaseNoire);
                        coupsPossiblesSansPrise.Add(unCoup);
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                /*Essais de voir si la possition de la pièce + la directionDeux est un coup valide*/
                try
                {
                    /*Si le coup est un déplacement*/
                    if ((Damier.damier[piece.position + directionDeux] is CaseNoire) && (Damier.damier[piece.position + directionDeux] as CaseNoire).estVide()) //test deplacement 2nd cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position + directionDeux] as CaseNoire);
                        coupsPossiblesSansPrise.Add(unCoup);
                    }
                    /*Si le coup dois manger*/
                    else if ((Damier.damier[piece.position + (directionDeux * 2)] as CaseNoire).estVide() && !this.lesPieces.Contains((Damier.damier[piece.position + (directionDeux)] as CaseNoire).piece) && !(Damier.damier[piece.position + directionDeux] as CaseNoire).estVide())//test manger 2nd cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position + (directionDeux * 2)] as CaseNoire, (Damier.damier[piece.position + directionDeux] as CaseNoire).piece);
                        coupsPossiblesAvecPrise.Add(unCoup);
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                try
                {
                    if (!(Damier.damier[piece.position - directionUn] as CaseNoire).estVide() && (Damier.damier[piece.position - (directionUn *2)] as CaseNoire).estVide()) //test manger arriere 1er cas
                    {
                        if (!this.lesPieces.Contains((Damier.damier[piece.position - (directionUn)] as CaseNoire).piece))
                        {
                            Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position - (directionUn * 2)] as CaseNoire, (Damier.damier[piece.position - directionUn] as CaseNoire).piece);
                            coupsPossiblesAvecPrise.Add(unCoup);
                        }
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                try
                {
                    if (!(Damier.damier[piece.position - directionDeux] as CaseNoire).estVide() && (Damier.damier[piece.position - (directionDeux * 2)] as CaseNoire).estVide()) //test manger arriere 2nd cas
                    {
                        if (!this.lesPieces.Contains((Damier.damier[piece.position - (directionDeux)] as CaseNoire).piece))
                        {
                            Coup unCoup = new Coup(this, Damier.damier[piece.position] as CaseNoire, Damier.damier[piece.position - (directionDeux * 2)] as CaseNoire, (Damier.damier[piece.position - directionDeux] as CaseNoire).piece);
                            coupsPossiblesAvecPrise.Add(unCoup);
                        }
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

            }
            if (coupsPossiblesAvecPrise.Count() != 0) //Si la liste des coups avec prises est non-vide.
            {
                this.coupsPossibles = coupsPossiblesAvecPrise;
                List<Coup> coupsAJouer = new List<Coup>();
                this.calculMangeageMultiple(ref coupsAJouer, damier, this.coupsPossibles);
                coupsPossibles = coupsAJouer;
            }
            else
            {
                this.coupsPossibles = coupsPossiblesSansPrise;
            }
        } //calculCoupsPossibles();

        public int calculMangeageMultiple(ref List<Coup> coupsAJouer, Damier damier, List<Coup> coupsPossibles, int profondeur = 0)
        {
            int mangerMax = -500;
            int nombreManger = 0;
            if (coupsPossibles.Count() == 0)
            {
                nombreManger = profondeur;
                return nombreManger;
            }
            foreach (Coup unCoup in coupsPossibles)
            {
                unCoup.origine.piece.mange(unCoup);
                List<Coup> apres = this.calculCoupsPossibleQuiMangentApres(unCoup, damier);
                nombreManger = calculMangeageMultiple(ref coupsAJouer, damier, apres, profondeur + 1);
                if (nombreManger > mangerMax)
                {
                    mangerMax = nombreManger;
                    coupsAJouer.Clear();
                    coupsAJouer.Add(unCoup);
                }
                else if (nombreManger == mangerMax)
                {
                     coupsAJouer.Add(unCoup);
                }
                damier.annulerMangage(unCoup);
                damier.afficheDamier();
            }
            return mangerMax;
        }

        public List<Coup> calculCoupsPossibleQuiMangentApres(Coup coup, Damier damier)
        {
            List<Coup> coupsPossiblesAvecPrise = new List<Coup>();

            // set les deux directions possibles suivant la couleur du joueur
            int directionUn = 11 * this.couleur;
            int directionDeux = 13 * this.couleur;
                /*Essais de voir si la possition de la pièce + la directionUn est un coup valide*/
                try
                {
                    /*Si le coup dois manger*/
                    if ((Damier.damier[coup.destination.position + (directionUn * 2)] as CaseNoire).estVide() && !this.lesPieces.Contains((Damier.damier[coup.destination.position + (directionUn)] as CaseNoire).piece) && !(Damier.damier[coup.destination.position + directionUn] as CaseNoire).estVide()) //test manger 1er cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[coup.destination.position] as CaseNoire, Damier.damier[coup.destination.position + (directionUn * 2)] as CaseNoire, (Damier.damier[coup.destination.position + directionUn] as CaseNoire).piece);
                        coupsPossiblesAvecPrise.Add(unCoup);
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                /*Essais de voir si la possition de la pièce + la directionDeux est un coup valide*/
                try
                {

                    /*Si le coup dois manger*/
                    if ((Damier.damier[coup.destination.position + (directionDeux * 2)] as CaseNoire).estVide() && !this.lesPieces.Contains((Damier.damier[coup.destination.position + (directionDeux)] as CaseNoire).piece) && !(Damier.damier[coup.destination.position + directionDeux] as CaseNoire).estVide())//test manger 2nd cas
                    {
                        Coup unCoup = new Coup(this, Damier.damier[coup.destination.position] as CaseNoire, Damier.damier[coup.destination.position + (directionDeux * 2)] as CaseNoire, (Damier.damier[coup.destination.position + directionDeux] as CaseNoire).piece);
                        coupsPossiblesAvecPrise.Add(unCoup);
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                try
                {
                    if (!(Damier.damier[coup.destination.position - directionUn] as CaseNoire).estVide() && (Damier.damier[coup.destination.position - (directionUn * 2)] as CaseNoire).estVide()) //test manger arriere 1er cas
                    {
                        if (!this.lesPieces.Contains((Damier.damier[coup.destination.position - (directionUn)] as CaseNoire).piece))
                        {
                            Coup unCoup = new Coup(this, Damier.damier[coup.destination.position] as CaseNoire, Damier.damier[coup.destination.position - (directionUn * 2)] as CaseNoire, (Damier.damier[coup.destination.position - directionUn] as CaseNoire).piece);
                            coupsPossiblesAvecPrise.Add(unCoup);
                        }
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                try
                {
                    if (!(Damier.damier[coup.destination.position - directionDeux] as CaseNoire).estVide() && (Damier.damier[coup.destination.position - (directionDeux * 2)] as CaseNoire).estVide()) //test manger arriere 2nd cas
                    {
                        if (!this.lesPieces.Contains((Damier.damier[coup.destination.position - (directionDeux)] as CaseNoire).piece))
                        {
                            Coup unCoup = new Coup(this, Damier.damier[coup.destination.position] as CaseNoire, Damier.damier[coup.destination.position - (directionDeux * 2)] as CaseNoire, (Damier.damier[coup.destination.position - directionDeux] as CaseNoire).piece);
                            coupsPossiblesAvecPrise.Add(unCoup);
                        }
                    }
                }
                catch (NullReferenceException) { }
                catch (IndexOutOfRangeException) { }

                //on affecte la liste des coups possibles et on y met la liste des coups qui mangent (même si vide)
                return coupsPossiblesAvecPrise;
            }

        public void afficheCoupsPossibles()
        {
            foreach (Coup unCoup in this.coupsPossibles)
            {
                Console.Write(unCoup+" ");
            }
            Console.WriteLine();
        }

        public bool equals(Joueur j)
        {
            return true;
        }
    }
}
